/**
 * 用于瀑布流滚动
 * 依赖文件有iptv.focus.js里的findFocusTarget flyFocus   iptv.utility.js里的 pageX pageY
 * 区块移动时需要在每个区块建个参照物
 */
;(function(undefined) {
    //先做依赖检测
    try{
        var _arrPredefinedVars = [$Focus.find,$Dom.query];
    }catch(err){
        console.log("依赖出现问题，无法使用plug.scroll.js");
        return null;
    }

    var _global;
    var _oDirectionMap = {//以数值，作为滚动方向的矢量 -1向前 1向后
        "vertical" : {
            "-1" : "up",
            "1" : "down",
            "up" : 1,
            "down" : -1,
            "pageOrientation" : "pageY",
            "size" : "height",
            "position" : "top",
            "backwardLimit" : $Focus.iFocusBottomLimit,
            "defaultDir" : "down"
        },
        "horizontal" : {
            "-1" : "left",
            "1" : "right",
            "left" : 1,
            "right" : -1,
            "pageOrientation" : "pageX",
            "size" : "width",
            "position" : "left",
            "backwardLimit" : $Focus.iFocusRightLimit,
            "defaultDir" : "right"
        },
    };
    
    function Scroll( options ) {
        return new Scroll.prototype.init( options);
    }
    Scroll.prototype = {
        constructor: Scroll,
        init: function( options) {
            this.slideByCheck = true;//默认给瀑布流列表加上transition的属性 然后通过定时器去check 配合下方targetPosition使用
            this.iElemTargetPosition = null;
            this.elem = null;//滚动元素
            this.anchor = 0;//滚动焦点元素对齐点 0是上方对齐 0.5是中间对齐，1是底部对齐 只发生在行滚动中
            this.elRef = document.body;//滚动参照元素
            this.iInitOffset = 0;
            this.iEasing = 0.3;//0.3最好是写到全局文件里头
            this.fnCb = null;//滚动完毕回调函数
            this.strSlideWay = "vertical";//vertical纵向滚动 horizontal 横向滚动
            for(var key in options){
                this[key] = options[key];// || this[key];
            }
            this.iAlighVal = this.iAlighVal || this.iInitOffset;//对齐值 只发生在行滚动中
            this.iSlideStatus = 0;//滚动状态
            this.oSlideDirMap = _oDirectionMap[this.strSlideWay];
            this.pageOrientation = this.oSlideDirMap.pageOrientation;
            this.strOffsetSize = this.oSlideDirMap.size;
            this.strPosition = this.oSlideDirMap.position;
            this.iSlideLimit = this.iSlideLimit || this.oSlideDirMap.backwardLimit;
            this.strDefalutDir = this.oSlideDirMap.defaultDir;
            this.strFocusScroll = "";
            this.unit = this.unit || "px";
            this.iSlideSize = this.elem[this.strOffsetSize]() || 10000;
            //生成头部参考焦点
            this.elCeilRef = this.createDom("waterfall_ceil_ref",{
                "position" : "absolute",
                "left" : (this.elRef.width()/2)+this.unit,
                "top" : (this.elem.top()-20)+this.unit,//从体验角度讲找最大焦点都是从上面开始找，所以这里用pageY了,-10是为了稍微保持点距离
                "width" : "1"+this.unit,
                "height" : "1"+this.unit
            },this.elRef);
            //生成侧边参考点
            this.elSideRef = this.createDom("waterfall_side_ref",{
                "position" : "absolute",
                "left" : (this.elRef.pageX()-50)+this.unit,
                "top" : (this.iAlighVal - this.iInitOffset)+this.unit,
                "width" : "100"+this.unit,
                "height" : "1"+this.unit
            });
            this.elFloorRef = this.createDom("waterfall_floor_ref",{
                "position" : "absolute",
                "left" : (this.elRef.width()/2)+this.unit,
                "top" : (this.iSlideSize + 20)+this.unit,//从体验角度讲找最大焦点都是从上面开始找，所以这里用pageY了,-10是为了稍微保持点距离
                "width" : "1"+this.unit,
                "height" : "1"+this.unit
            },this.elRef);

            if(this.strSlideWay == "horizontal"){
                this.elCeilRef.left(-this.elem.width());
                this.elCeilRef.top(this.elRef.height()/2);

                this.elFloorRef.left(this.iSlideSize + 20);
                this.elFloorRef.top(this.elRef.height()/2);
            }
            this.iCeilInitPosition = this.elCeilRef[this.strPosition]();
            this.timerShowFocus = null;
        },
        /**
         * 创建dom元素
         * @param {domid} id 
         * @param {dom样式} oStyle 
         * @param {dom父元素} elParent 
         */
        createDom : function(id,oStyle,elParent){
            var el = $Dom.create("div");
            el.id = id;
            for(var key in oStyle){
                el.style[key] = oStyle[key];
            }
            elParent = elParent || document.body;
            elParent.appendChild(el);
            return el;
        },
        /**
         * 设置瀑布流回调函数
         * @param {回调函数} fn 
         */
        setFnCb : function(fn){
            this.fnCb = fn;
        },
        /**
         * 定时器处理滚动回调
         * @param {回调函数} fn 
         */
        slide : function(oScrollParameter){
            this.iSlideStatus = 1;
            var _this = this;
            if(this.timerShowFocus){
                window.clearTimeout(this.timerShowFocus);
            }
            
            if(oScrollParameter){
                var bHasTime = _this.iEasing !=0;
                var fnCb = function(){
                    _this.elCeilRef[_this.strPosition]( (_this.iCeilInitPosition + _this.elem[_this.strPosition]() - _this.iInitOffset)+_this.unit );
                    _this.iSlideStatus = 0;
                    _this.fnCb&&_this.fnCb();
                    // if(bHasTime){
                    //     _this.timerShowFocus = window.setTimeout(function(){
                    //         $Focus.show();
                    //     },iDelay);
                    // }else{
                    //     $Focus.show();
                    // }
                   
                }
                if(this.slideByCheck){
                    if(_this.iEasing > 0){
                        //$Focus.hide();
                        this.iElemTargetPosition = this.elem[_this.strPosition]()-this.oSlideDirMap[oScrollParameter.direction]*oScrollParameter.step;
                        this.checkScrollPosition(fnCb);
                    }else{
                        oScrollParameter.cb = fnCb
                    }
                    
                }else{
                    oScrollParameter.speed = this.iEasing*1000;
                    oScrollParameter.cb = fnCb;
                }
            }else{
                _this.iSlideStatus = 0;
                _this.fnCb&&_this.fnCb();
                $Focus.show();
            }
        },
        /**
         * 检测瀑布流滚动到的位置
         * @param {*} fnCb 
         */
        checkScrollPosition : function(fnCb){
            var _this = this;
            window.setTimeout(function(){
                if(_this.iElemTargetPosition == _this.elem[_this.strPosition]()){
                    fnCb&&fnCb();
                }else{
                    _this.checkScrollPosition(fnCb);
                }
            },13);
        },
        /**
         * 一行一行滚动
         * @param {目标焦点} elTarget 
         * @param {滚动方向} strKeyDirection 一般不需要特别指定，因为处理了一个比较业务的需求，所以向下滚动的时候需要特别传下方向参数
         */
        slideByRow : function(elTarget,strKeyDirection){
            var elCurrent = document.getElementById($Focus.strFocusElementId);
            var oScrollParameter = null;
            var iDir = parseFloat((elTarget[this.pageOrientation]() - elCurrent[this.pageOrientation]())/Math.abs((elTarget[this.pageOrientation]() - elCurrent[this.pageOrientation]())));//得出-1还是1
            var strDir = this.oSlideDirMap[iDir+""];
            // if(iDir == 1&&strKeyDirection == strDir){//向下找还要贴左边找
            //     //感觉这一段写在插件里面不好，比较业务，应该写外头，多做一个处理，主要是处理左边往下焦点靠左的需求
            //     if(elCurrent.offsetLeft < 50){
            //         //调整侧边参照物
            //         this.elSideRef.style[this.strPosition] = (elCurrent[this.pageOrientation]()+20)+this.unit;
            //         elTarget = $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, strDir,this.elSideRef);
            //     }
            // }
            //一般发生在顶层不再有瀑布流元素时，不做滚动，滚动可能导致回不到起始点
            if((null == $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, this.oSlideDirMap["-1"],elTarget)&&elTarget[this.pageOrientation]() > 0)
            ){
                return elTarget;
            }
            if(iDir){
                if(
                    (elTarget[this.pageOrientation]() > this.elRef[this.strPosition]()+this.iInitOffset+this.iAlighVal&&iDir==-1)
                    
                    ||(this.iSlideSize - this.iSlideLimit+this.elem[this.pageOrientation]() <= 0&&iDir == 1)
                ){
                    //到达极限不发生滚动
                }else{
                    oScrollParameter = {
                        element : this.elem,
                        direction : this.oSlideDirMap[-iDir+""],
                        relation : true,
                        step : elTarget[this.pageOrientation]() - this.elRef[this.pageOrientation]()-this.iAlighVal+this.anchor*elTarget[this.strOffsetSize]()
                    }
                    
                    if(iDir == 1){
                        
                        //底部不能超出
                        if(oScrollParameter.step - this.elem[this.pageOrientation]() > this.iSlideSize - this.iSlideLimit){
                            oScrollParameter.step = this.iSlideSize - this.iSlideLimit +  this.elem[this.pageOrientation]();
                        }
                    
                    }
                    //顶部不能超出
                    if(this.elem[this.strPosition]() - oScrollParameter.step > this.iInitOffset){
                        oScrollParameter.step = -this.iInitOffset + this.elem[this.strPosition]();
                    }
                    oScrollParameter.step = iDir*oScrollParameter.step;
                }
            }
            if(oScrollParameter&&oScrollParameter.step){
                if(this.strSlideWay == "vertical"&&Math.abs(oScrollParameter.step) < 50){//纵向滚动距离太小则不考虑滚动,调一个合适的值
                    oScrollParameter = null;
                    return elTarget;
                }else{
                    this.slide(oScrollParameter);
                    $Focus.fly(elTarget, strDir, $Focus.fScaleFactor, oScrollParameter);//这里的方向不是很有关系
                    return null;
                }
                
            }else{
                return elTarget;
            }
        },
        /**
         * 判断是不是到底部了
         */
        isFloor : function(){
            return -this.elem[this.strPosition]() >= this.iSlideSize - this.iSlideLimit;
        },
        /**
         * 一区块一区块滚动 一整块不考虑焦点元素的对齐方式 区块移动需要参照点做辅助
         * @param {目标焦点} elTarget 
         * @param {滚动方向} strKeyDirection 一般不需要特别指定，因为处理了一个比较业务的需求，所以向下滚动的时候需要特别传下方向参数
         */
        slideByBlock : function(elTarget,strKeyDirection){
            var elCurrent = document.getElementById($Focus.strFocusElementId);
            var iFloorCurrent = $Focus.strFocusElementId.match(/\d+/g)[0];
            var arrLevel = elTarget.id.match(/\d+/g);
            var iFloorTarget = arrLevel[0];
            // if(iFloorCurrent == iFloorTarget&&iFloorTarget!=0){//同一层直接返回不再做判断
            //     return elTarget;
            // }
            
            var oScrollParameter = null;
            var iDir = parseFloat((elTarget[this.pageOrientation]() - elCurrent[this.pageOrientation]())/Math.abs((elTarget[this.pageOrientation]() - elCurrent[this.pageOrientation]())));//得出-1还是1
            var strDir = this.oSlideDirMap[iDir+""];
            var elRefEle;
            //代码已被我越改越乱，我相信再牛逼的人也没办法被这样改来改去，我唯一能做的就是别发火，千万别发火
            
            
            // if(arrLevel.length >=3){
            //     var strId = elTarget.id.replace(/([a-zA-Z1-9]+_\d+_[a-zA-Z1-9]+_\d+).*/g,"$1");
            //     elRefEle = $Dom.getById(strId);
            // }else
            if(iFloorTarget == 0){
                elRefEle = $Dom.getById(elTarget.id.replace(/([a-zA-Z1-9]+_\d+)_[a-zA-Z1-9]+_\d+.*/g,"$1"));//为了寻找最大的焦点
            }else{
                elRefEle = $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, this.strDefalutDir,$Dom.getById("nothing_"+iFloorTarget));
            }
            // if(iDir == 1&&strKeyDirection == strDir){//向下找还要贴左边找
            //     //感觉这一段写在插件里面不好，比较业务，应该写外头，多做一个处理，主要是处理左边往下焦点靠左的需求
            //     if(elCurrent.offsetLeft < 50){
            //         //调整侧边参照物
            //         this.elSideRef.style[this.strPosition] = (elCurrent[this.pageOrientation]()+20)+this.unit;
            //         elTarget = $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, strDir,this.elSideRef);
            //     }
            // }
            if(iDir == 1&&this.iSlideSize + this.elem[this.strPosition]() + this.elRef[this.pageOrientation]()+this.iInitOffset <= this.iSlideLimit){

            }else{
                oScrollParameter = {
                    element : this.elem,
                    direction : this.oSlideDirMap[-iDir+""],
                    relation : true,
                    step : elRefEle[this.pageOrientation]()-this.elRef[this.pageOrientation]()-this.iInitOffset
                }
               

                //底部不能超出
                if(
                    elTarget[this.pageOrientation]() > this.elRef[this.strPosition]()+this.iInitOffset
                    &&(oScrollParameter.step - this.elem[this.pageOrientation]() > this.iSlideSize - this.iSlideLimit)){
                    oScrollParameter.step = this.iSlideSize - this.iSlideLimit + this.elem[this.pageOrientation]();
                }
                oScrollParameter.step = iDir*oScrollParameter.step;
            }
            if(oScrollParameter&&oScrollParameter.step){
                this.slide(oScrollParameter);
                $Focus.fly(elTarget, strDir, $Focus.fScaleFactor, oScrollParameter);
                //this.runTimer();
                return null;
            }else{
                return elTarget;
            }
        },
        /**
         * 获取瀑布流滚动方向坐标值
         */
        getElementTop : function(){
            return parseFloat(this.elem.style[this.strPosition]);
        },
        /**
         * 获取瀑布流滚动状态
         */
        getSlideStatus : function(){
            return this.iSlideStatus;
        },
        /**
         * 回到瀑布流初始点
         */
        go2Ceil : function(){
            this.iSlideStatus = 1;
            var elRef = this.elCeilRef;
            var elTarget = $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, this.oSlideDirMap.defaultDir,elRef);//从体验角度讲找最大焦点都是从上面开始找，所以这里用pageY了,-10是为了稍微保持点距离
            var oScrollParameter = {
                element : this.elem,
                direction : this.oSlideDirMap.defaultDir,
                relation : true,
                step : this.iInitOffset-this.elem[this.strPosition]()
            }
            this.slide(oScrollParameter);
            $Focus.fly(elTarget, this.strDefalutDir, $Focus.fScaleFactor, oScrollParameter);
        },
        /**
         * 直接到瀑布流尾部
         */
        go2Floor : function(){
            this.iSlideStatus = 1;
            var elRef = this.elFloorRef;
            var strDir = this.oSlideDirMap[this.oSlideDirMap[this.oSlideDirMap.defaultDir]];
            var elTarget = $Focus.find($Focus.aFocusTargets,$Focus.iFocusStatus, strDir ,elRef);//从体验角度讲找最大焦点都是从上面开始找，所以这里用pageY了,-10是为了稍微保持点距离
            var oScrollParameter = {
                element : this.elem,
                direction : strDir,
                relation : true,
                step : this.iSlideSize - this.iSlideLimit - this.iInitOffset + this.elRef[this.pageOrientation]() + this.elem[this.strPosition]()
            }
            this.slide(oScrollParameter);
            $Focus.fly(elTarget, this.strDefalutDir, $Focus.fScaleFactor, oScrollParameter);
        },
        /**
         * 设置瀑布流高度
         * @param {高度值} val 
         */
        setSlideHeight : function(val){
            this.iSlideSize = parseFloat(val);
        },
        /**
         * 重置瀑布流
         */
        reset : function(){
            this.elem.style[this.strPosition] = this.iInitOffset + "px";
            this.iSlideSize = this.elem[this.strOffsetSize]() || 10000;
            this.fnCb&&this.fnCb();
        },
        /**
         * 设置对齐值
         * @param {*} val 
         */
        setAlignValue : function(val){
            this.iAlighVal = val;
        },
        /**
         * 设置对齐中心点
         * @param {*} val 
         */
        setAnchor : function(val){
            this.anchor = val;
        }

    };
    
    Scroll.prototype.init.prototype = Scroll.prototype;
    _global = (function(){ return this || (0, eval)('this'); }());
    if (typeof module !== "undefined" && module.exports) {
        module.exports = Scroll;
    } else if (typeof define === "function" && define.amd) {
        define(function(){return Scroll;});
    } else {
        !('Scroll' in _global) && (_global.Scroll = Scroll);
    }
}());
